#include "StdAfx.h"
#include "resource.h"
#include "AppWindow.h"
#include <vector>
#include <algorithm>
#include "Enviroment.h"
#include "Win32InputInjector.h"
#include "Win32Clipboard.h"
#include "UIEnv.h"

IMPLEMENT_Singleton(VWD::AppWindow);
using namespace VWD;

#pragma region Win32 jobs

#define MAX_LOADSTRING 100
#define DEFAULT_WINDOW_WIDTH 1024
#define DEFAULT_WINDOW_HEIGHT 768
TCHAR szTitle[MAX_LOADSTRING];		
TCHAR szWindowClass[MAX_LOADSTRING];

HINSTANCE hInst;	
int cmdShow;
ATOM				MyRegisterClass(HINSTANCE hInstance);
BOOL				InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
bool looping = true;

void MsgPump()
{
	MSG msg;
	
	Ogre::Root* pRoot =Ogre::Root::getSingletonPtr();

	while (looping)//GetMessage(&msg, NULL, 0, 0)) 
	{       
		if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)==0)
		{
			looping = (Enviroment::RenderWindow!=0) && (!Enviroment::RenderWindow->isClosed()) && pRoot->renderOneFrame();
		}
		else
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
}

ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX); 

	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= (WNDPROC)WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, (LPCTSTR)IDI_OVERLOOK);
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)CreateSolidBrush(0);
	wcex.lpszMenuName	= NULL;
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);

	return RegisterClassEx(&wcex);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static bool doSizing = false;
	switch(message)
	{
	case WM_SIZE:
	case WM_MOVE:
	case WM_DISPLAYCHANGE:
		doSizing = true;
		break;
	default:
		if(doSizing)		
		{
			Enviroment::RenderWindow->windowMovedOrResized();					
			{
				using namespace Ogre;
				WindowEventUtilities::WindowEventListeners::iterator 
					i=WindowEventUtilities::_msListeners.begin(),
					end=WindowEventUtilities::_msListeners.end();
				while(i!=end)
				{
					i->second->windowResized(Enviroment::RenderWindow);
					i++;
				}
				
			}			
		}
		doSizing=false;
		break;
	}
	
	switch (message) 
	{		
	case WM_SETCURSOR:
		if(VWD::UIEnv::getInstanceRef().isUsingSystemCursor())
		{
			SetCursor(VWD::UIEnv::getInstanceRef().getCurrentSystemCursor());
		}
		break;
	case WM_ACTIVATE:
		if(LOWORD(wParam)==WA_INACTIVE)
		{
			if((BOOL)HIWORD(wParam)==TRUE)
			{
				Enviroment::RenderWindow->setActive(false);
			}
		}
		else
		{
			Enviroment::RenderWindow->setActive(true);
		}
		break;
	case WM_CLOSE:
		looping=false;
		break;
	case WM_DESTROY: 
		PostQuitMessage(0);
		break;
	default:				
		if(!Enviroment::OnWin32Msg.empty())
		{
			HRESULT hr = Enviroment::OnWin32Msg(hWnd,message,wParam,lParam);
			if(hr==0)
				return DefWindowProc(hWnd, message, wParam, lParam);
			else
				return hr;
		}
		else
			return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

#pragma endregion

VWD::AppWindow::AppWindow(void)
{
}

VWD::AppWindow::~AppWindow(void)
{
}

VWD::Win32InputInjector *inputInjector;
VWD::Win32Clipboard *clipboard;

size_t VWD::AppWindow::CreateAppWindow()
{
	HWND hWnd;

	LoadString(hInst, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadString(hInst, IDS_CLASS_NAME, szWindowClass, MAX_LOADSTRING);

	MyRegisterClass(hInst);
	hWnd = CreateWindow(
		szWindowClass, 
		szTitle, 
		WS_OVERLAPPEDWINDOW
		//WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX 
		//| WS_MAXIMIZEBOX
		,
		CW_USEDEFAULT, 0, DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT, NULL, NULL, hInst, NULL);

	Ogre::Root* pRoot = new Ogre::Root();

	if(!pRoot->restoreConfig())
	{
		if(pRoot->showConfigDialog())
			pRoot->saveConfig();
		else
			return 0;
	}

	pRoot->initialise(false,"VWD");	

	Ogre::NameValuePairList misc;
	misc["externalWindowHandle"] = Ogre::StringConverter::toString( (size_t)hWnd);
	
	Enviroment::RenderWindow = pRoot->createRenderWindow( "Main Render Window", DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT, false, &misc );
	Ogre::WindowEventUtilities::_addRenderWindow(Enviroment::RenderWindow);	
	ShowWindow(hWnd, cmdShow);
	UpdateWindow(hWnd);

	inputInjector = new Win32InputInjector(hWnd);
	clipboard = new Win32Clipboard(hWnd);

	return (size_t)hWnd;
}

void VWD::AppWindow::SetHinstance( size_t hinstance )
{
	hInst = (HINSTANCE)hinstance;
}

void VWD::AppWindow::SetCmdShow( int cs )
{
	cmdShow = cs;
}

void VWD::AppWindow::StartRendering()
{
	MsgPump();
}

void VWD::AppWindow::StopRendering()
{
	looping = false;
}